﻿#include "FileMesh.h"
#include "Logging.h"
#include "Timer.h"
#include <fstream>
#include <sstream>

#include <vtkm/cont/DataSet.h>
#include <vtkm/cont/DataSetBuilderExplicit.h>
#include <vtkm/worklet/WorkletMapField.h>

RegisterObject(FileMesh);

struct BuildBndWorklet : vtkm::worklet::WorkletMapField
{
  using ControlSignature = void(FieldIn point, FieldOut list);
  using ExecutionSignature = void(_1, _2);

  template<typename PType>
  VTKM_EXEC
  void operator()(const PType& p, vtkm::Id& bid) const
  {
    if (vtkm::Abs(p[0] - _x_min) < _tol) // left
    {
      bid = 3;
    }
    else if (vtkm::Abs(p[0] - _x_max) < _tol) // right
    {
      bid = 1;
    }
    else if (vtkm::Abs(p[1] - _y_min) < _tol) // bottom
    {
      bid = 0;
    }
    else if (vtkm::Abs(p[1] - _y_max) < _tol) // top
    {
      bid = 2;
    }
    else // 内部点
    {
      bid = -1;
    }
  }

private:
  vtkm::FloatDefault _x_min = 0, _x_max = 1, _y_min = 0, _y_max = 1;
  vtkm::FloatDefault _tol = 1E-06;
};

struct Transform : vtkm::worklet::WorkletMapField
{
  using ControlSignature = void(FieldInOut point);
  using ExecutionSignature = void(_1);

  template<typename PType>
  VTKM_EXEC void operator()(PType& p) const
  {
    p /= PType{ 6.226500, 6.226500, 1 };
  }
};

  void FileMesh::Build()
{
  Timer timer;
  timer.Start();

  std::ifstream ifile;
  ifile.open(_node_file);
  if (!ifile)
  {
    Error(_node_file, "打开错误");
  }

  std::string line;

  std::vector<vtkm::Vec3f> coords;
  std::vector<vtkm::Vec3f> velocity;
  while (std::getline(ifile, line))
  {
    int id;
    float x, y, u, v;

    if (line.empty()) // 跳过空行
      continue;

    if (line.find("格点编号") != std::string::npos) //跳过第一行
      continue;

    std::istringstream ss(line);
    ss >> id >> x >> y >> u >> v;
    coords.push_back({ x, y, 0 });
    velocity.push_back({ u, v, 0 });
  }
  ifile.close();
  Success("读取点文件完成，点数: ", coords.size());

  ifile.open(_cell_file);
  if (!ifile)
  {
    Error(_cell_file, "打开错误");
  }

  std::vector<vtkm::UInt8> shapes;
  std::vector<vtkm::IdComponent> numindices;
  std::vector<vtkm::Id> conn;
  std::vector<vtkm::FloatDefault> pressure, temperature;
  while (std::getline(ifile, line))
  {
    int id;
    int vertex[3];
    int material_id;
    float pre, temp;

    if (line.empty()) // 跳过空行
      continue;

    if (line.find("单元编号") != std::string::npos) //跳过第一行
      continue;

    std::istringstream ss(line);
    ss >> id >> vertex[0] >> vertex[1] >> vertex[2] >> material_id >> pre >> temp;
    shapes.push_back(vtkm::CELL_SHAPE_TRIANGLE);
    numindices.push_back(3);
    conn.push_back(vertex[0] - 1);
    conn.push_back(vertex[1] - 1);
    conn.push_back(vertex[2] - 1);
    pressure.push_back(pre);
    temperature.push_back(temp);
  }
  ifile.close();
  Success("读取单元文件完成，单元数: ", shapes.size());

  vtkm::cont::DataSet dataSet;
  vtkm::cont::DataSetBuilderExplicit dsb;
  dataSet = dsb.Create(coords, shapes, numindices, conn, "coordinates");
  dataSet.AddPointField("velocity", velocity);
  dataSet.AddCellField("pressure", pressure);
  dataSet.AddCellField("temperature", temperature);

  //_coord = vtkm::cont::CoordinateSystem("coordinate",
  //                                      vtkm::cont::make_ArrayHandle(coords, vtkm::CopyFlag::On));
  _coord = dataSet.GetCoordinateSystem();
  
  _cell_set = dataSet.GetCellSet();

  // 边界点
  vtkm::cont::Invoker{}(BuildBndWorklet{}, _coord, _boundary_id);

  vtkm::cont::Invoker{}(Transform{}, _coord);

  Info("读取网格完成，运行时间: ", timer.GetElapsedTime());
}

//void FileMesh::BuildBndList()
//{
//  vtkm::cont::Invoker{}(BuildBndWorklet{}, _coord, _boundary_id);
//}
